//给你一个整数数组 nums 和一个整数 target 。
//
// 向数组中的每个整数前添加 '+' 或 '-' ，然后串联起所有整数，可以构造一个 表达式 ：
//
//
// 例如，nums = [2, 1] ，可以在 2 之前添加 '+' ，在 1 之前添加 '-' ，然后串联起来得到表达式 "+2-1" 。
//
//
// 返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
//
//
//
// 示例 1：
//
//
//输入：nums = [1,1,1,1,1], target = 3
//输出：5
//解释：一共有 5 种方法让最终目标和为 3 。
//-1 + 1 + 1 + 1 + 1 = 3
//+1 - 1 + 1 + 1 + 1 = 3
//+1 + 1 - 1 + 1 + 1 = 3
//+1 + 1 + 1 - 1 + 1 = 3
//+1 + 1 + 1 + 1 - 1 = 3
//
//
// 示例 2：
//
//
//输入：nums = [1], target = 1
//输出：1
//
//
//
//
// 提示：
//
//
// 1 <= nums.length <= 20
// 0 <= nums[i] <= 1000
// 0 <= sum(nums[i]) <= 1000
// -1000 <= target <= 1000
//
//
// Related Topics 数组与矩阵 动态规划 回溯与递归 👍 1627 👎 0


//leetcode submit region begin(Prohibit modification and deletion)
function findTargetSumWays(nums: number[], target: number): number {

    /*?
        ? 加法和为x 减法和为sum - x => x - (sum - x) = target => x = (target  + sum) / 2
        ? 即dp表示装满(target + sum) / 2容量的背包有多少种方法
        ? dp[j] 表示：填满j（包括j）这么大容积的包，有dp[j]种方法
    ?*/
    const sum : number = nums.reduce((a,b) => a + b)
    if ((sum + target) % 2 || Math.abs(target) > sum)  return 0;  //? 无解的情况
    const bagSize : number = (target + sum) / 2
    const dp : number[] = new Array(bagSize + 1).fill(0)
    dp[0] = 1
    for (let i = 0; i < nums.length; i ++) {
        for (let j = bagSize; j >= nums[i]; j --) {
            //? 在求装满背包有几种方法的情况下，递推公式一般为：
            //? dp[j] += dp[j - nums[i]]
            //? 当前值为num[i] => 剩下总容量为bagSize - num[i] 此时dp[bagSize - num[i]]就是装满当前剩余容量的背包有的方法数
            //? 为什么累加呢?
            //? 解释：表示能凑出和为 j 的方案数应该为：不选 nums[i] 的方案数(dp[j]) 加上选择 nums[i] 的方案数 (dp[j-nums[i]])
            dp[j] += dp[j - nums[i]]
        }
    }
    return dp[bagSize]
};
//leetcode submit region end(Prohibit modification and deletion)
